package com.yang.frost.raspberry.shiro.service.impl;

import com.yang.frost.raspberry.constant.CommonRedisKey;
import com.yang.frost.raspberry.domain.ClientInfo;
import com.yang.frost.raspberry.shiro.jwt.JwtToken;
import com.yang.frost.raspberry.shiro.service.LoginRedisService;
import com.yang.frost.raspberry.shiro.vo.JwtTokenRedisVo;
import com.yang.frost.raspberry.shiro.vo.LoginSysUserRedisVo;
import com.yang.frost.raspberry.util.ClientInfoUtil;
import com.yang.frost.raspberry.util.HttpServletRequestUtil;
import com.yang.frost.raspberry.vo.LoginSysUserVo;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;
import java.util.Set;

/**
 * @author 10296
 * @date 2020/12/24
 * @Description:
 */
@Service
public class LoginRedisServiceImpl implements LoginRedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * key-value:有过期时间-->token过期时间
     * 1.tokenMd5
     * 2.username
     * 3. username:salt
     * hash:没有过期时间统计在线用户信息
     *
     * @param jwtToken
     * @param loginSysUserVo
     */
    @Override
    public void cacheLoginInfo(JwtToken jwtToken, LoginSysUserVo loginSysUserVo) {

        if (jwtToken == null) {
            throw new IllegalArgumentException("jwtToken 不能为空！");
        }
        if (loginSysUserVo == null) {
            throw new IllegalArgumentException("LoginSysUserVo 不能为空！");
        }
        /*token*/
        String token = jwtToken.getToken();
        /*盐值*/
        String salt = jwtToken.getSalt();
        /*登录用户名称*/
        String username = loginSysUserVo.getUsername();
        /*token md5值*/
        String tokenMd5 = DigestUtils.md5Hex(token);
        //Redis 缓存JWT Token信息
        JwtTokenRedisVo jwtTokenRedisVo = new JwtTokenRedisVo();
        jwtTokenRedisVo.setHost(jwtToken.getHost());
        jwtTokenRedisVo.setUsername(jwtToken.getUsername());
        jwtTokenRedisVo.setSalt(jwtToken.getSalt());
        jwtTokenRedisVo.setToken(jwtToken.getToken());
        jwtTokenRedisVo.setCreateDate(jwtToken.getCreateDate());
        jwtTokenRedisVo.setExpireDate(jwtToken.getExpireDate());
        jwtTokenRedisVo.setExpireSecond(jwtToken.getExpireSecond());
        //用户客户端信息
        ClientInfo clientInfo = ClientInfoUtil.get(HttpServletRequestUtil.getServletRequest());
        /*Redis 缓存登录信息
         * i将LoginSysUserVo对象赋值到LoginSysUserRedisVo中
         * */
        LoginSysUserRedisVo userRedisVo = new LoginSysUserRedisVo();
        userRedisVo.setUsername(loginSysUserVo.getUsername());
        userRedisVo.setState(loginSysUserVo.getState());
        userRedisVo.setRoleName(loginSysUserVo.getRoleName());
        userRedisVo.setRoleId(loginSysUserVo.getRoleId());
        userRedisVo.setRoleCode(loginSysUserVo.getRoleCode());
        userRedisVo.setPermissionCodes(loginSysUserVo.getPermissionCodes());
        userRedisVo.setNickname(loginSysUserVo.getNickname());
        userRedisVo.setId(loginSysUserVo.getId());
        userRedisVo.setGender(loginSysUserVo.getGender());
        userRedisVo.setDepartmentName(loginSysUserVo.getDepartmentName());
        userRedisVo.setDepartmentId(loginSysUserVo.getDepartmentId());
        userRedisVo.setClientInfo(clientInfo);
        userRedisVo.setSalt(salt);
        /*Redis过期时间与J问题Token过期时间一致*/
        Duration expireDuration = Duration.ofSeconds(jwtToken.getExpireSecond());
        boolean singleLogin = true;
        if (singleLogin) {
            deleteUserAllCache(username);
        }
        String loginTokenRedisKey = String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5);
        /*1. tokenMd5 jwtTokenRedisVo*/
        redisTemplate.opsForValue().set(loginTokenRedisKey, jwtTokenRedisVo, expireDuration);
        /*2. username：*/
        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_USER, username), userRedisVo, expireDuration);
        // 3. salt hash,方便获取盐值鉴权
        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_SALT, username), salt, expireDuration);
        // 4. login user token
        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_USER_TOKEN, username, tokenMd5), loginTokenRedisKey, expireDuration);

    }

    @Override
    public void refreshLoginInfo(String oldToken, String username, JwtToken newJwtToken) {

        //获取缓存的登录用户信息
        LoginSysUserRedisVo userRedisVo = getLoginSysUserRedisVo(username);
        //删除之前的token信息
        deleteLoginInfo(oldToken, username);
        //缓存登录信息
        cacheLoginInfo(newJwtToken, userRedisVo);


    }

    @Override
    public LoginSysUserRedisVo getLoginSysUserRedisVo(String username) {
        if (StringUtils.isEmpty(username)) {
            throw new IllegalArgumentException("username 不能为空!");
        }
        LoginSysUserRedisVo userRedisVo = (LoginSysUserRedisVo) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_USER, username));

        return userRedisVo;
    }

    @Override
    public LoginSysUserVo getLoginSysUserVo(String username) {
        if (StringUtils.isEmpty(username)) {
            throw new IllegalArgumentException("username 不能为空！");
        }
        LoginSysUserRedisVo userRedisVo = getLoginSysUserRedisVo(username);

        return userRedisVo;
    }

    @Override
    public String getSalt(String username) {
        if (StringUtils.isEmpty(username)) {
            throw new IllegalArgumentException("username 不能为空!");
        }
        String salt = (String) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_SALT, username));
        return salt;
    }

    @Override
    public void deleteLoginInfo(String token, String username) {

        if (token == null) {
            throw new IllegalArgumentException("token 不能为空！");
        }
        if (username == null) {
            throw new IllegalArgumentException("username 不能为空!");
        }
        String tokenMd5 = DigestUtils.md5Hex(token);
        /*1. 删除tokenMd5*/
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5));
        /*2. 删除username*/
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER, username));
        /*3. 删除salt*/
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_SALT, username));
        /*4. 删除user token*/
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER_TOKEN, username, tokenMd5));


    }

    @Override
    public boolean exists(String token) {
        if (token == null) {
            throw new IllegalArgumentException("token  不能为空!");
        }
        String tokenMd5 = DigestUtils.md5Hex(token);
        Object obj = redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5));

        return obj != null;
    }

    @Override
    public void deleteUserAllCache(String username) {
        Set<String> userTokenMd5Set = redisTemplate.keys(String.format(CommonRedisKey.LOGIN_USER_ALL_TOKEN, username));
        if (CollectionUtils.isEmpty(userTokenMd5Set)) {
            return;
        }
        //1.删除登录用户的所有token信息
        List<String> tokenMd5List = redisTemplate.opsForValue().multiGet(userTokenMd5Set);
        redisTemplate.delete(tokenMd5List);
        /*2. 删除登录用户的所有user:token信息*/
        redisTemplate.delete(userTokenMd5Set);
        /*3. 删除登录用户信息*/
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER, username));
        /*4. 删除登录用户盐值信息*/
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_SALT, username));


    }
}
